package com.whmskj.xjlhsc.mobie.empProPlan.service.impl;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.util.StringUtil;
import com.whmskj.xjlhbc.domain.Yg01employeefiles;
import com.whmskj.xjlhbc.service.Yg01employeefilesService;
import com.whmskj.xjlhsc.entity.Groupattendancestatisticsforjx02;
import com.whmskj.xjlhsc.entity.Grouptableyg02;
import com.whmskj.xjlhsc.entity.Jx01staffattendancelog;
import com.whmskj.xjlhsc.enums.ScEnums;
import com.whmskj.xjlhsc.exception.BusinessException;
import com.whmskj.xjlhsc.exception.ExceptionText;
import com.whmskj.xjlhsc.jitapi.dto.Emp;
import com.whmskj.xjlhsc.jitapi.entity.Device;
import com.whmskj.xjlhsc.jitapi.entity.Dict;
import com.whmskj.xjlhsc.jitapi.mapper.ClassGroupMapper;
import com.whmskj.xjlhsc.jitapi.mapper.DeviceMapper;
import com.whmskj.xjlhsc.jitapi.mapper.DictMapper;
import com.whmskj.xjlhsc.jitapi.mapper.EmpMapper;
import com.whmskj.xjlhsc.mapper.*;
import com.whmskj.xjlhsc.mobie.empProPlan.controller.fo.StandConfirmation;
import com.whmskj.xjlhsc.mobie.empProPlan.dto.ScanDeviceDto;
import com.whmskj.xjlhsc.mobie.empProPlan.dto.ScanDeviceSignDto;
import com.whmskj.xjlhsc.mobie.empProPlan.entity.ProPersonnelStand;
import com.whmskj.xjlhsc.mobie.empProPlan.entity.ProPersonnelStandConfirm;
import com.whmskj.xjlhsc.mobie.empProPlan.entity.ProPersonnelStandMachine;
import com.whmskj.xjlhsc.mobie.empProPlan.mapper.ProPersonnelStandConfirmMapper;
import com.whmskj.xjlhsc.mobie.empProPlan.mapper.ProPersonnelStandMapper;
import com.whmskj.xjlhsc.mobie.empProPlan.service.ProPersonnelStandConfirmService;
import com.whmskj.xjlhsc.mobie.empProPlan.service.ProPersonnelStandMachineService;
import com.whmskj.xjlhsc.mobie.empProPlan.service.ProPersonnelStandService;
import com.whmskj.xjlhsc.mobie.empProPlan.service.ScanScheduleShiftsService;
import com.whmskj.xjlhsc.mobie.personnelFile.mapper.LeaveApplicationMapper;
import com.whmskj.xjlhsc.service.Jx01staffattendancelogService;
import com.whmskj.xjlhsc.utils.SCUtil;
import com.whmskj.xjlhsc.utils.SCUtil.ClassTimeRange;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @BelongsProject: XJLHSC
 * @BelongsPackage: com.whmskj.xjlhsc.mobie.empProPlan.service.impl
 * @Author: lk
 * @CreateTime: 2025-07-07
 * @Description: TODO
 * @Version: 1.0
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ScanScheduleShiftsServiceImpl implements ScanScheduleShiftsService {


    @Autowired
    private Yg01employeefilesService yg01employeefilesService;
    @Autowired
    private ProPersonnelStandConfirmMapper proPersonnelStandConfirmMapper;

    private final DeviceMapper deviceMapper;
    private final ProPersonnelStandConfirmService confirmService;
    private final ObjectMapper json;
    private final DictMapper dictMapper;
    private final EmpMapper empMapper;
    private final ClassGroupMapper classGroupMapper;
    private final ProPersonnelStandService proPersonnelStandService;
    private final ProPersonnelStandMachineService personnelStandMachineService;

    @Override
    public ScanDeviceSignDto getScanToDeviceList(Integer deviceId) {
        ScanDeviceSignDto scanDeviceSignDto = new ScanDeviceSignDto();
        Emp emp = SCUtil.getCurrentLoginEmp();
        ClassTimeRange range = SCUtil.getClassDateTimeRange();
        LambdaQueryWrapper<Yg01employeefiles> yg01LambdaQueryWrapper = new LambdaQueryWrapper<>();
        yg01LambdaQueryWrapper.eq(Yg01employeefiles::getId, emp.getEmpId());
        Yg01employeefiles yg01employeefiles = yg01employeefilesService.getOne(yg01LambdaQueryWrapper);
        boolean flag = ObjectUtil.isNotEmpty(yg01employeefiles) && ObjectUtil.isNotEmpty(yg01employeefiles.getProductionOfStaff()) && yg01employeefiles.getProductionOfStaff().equals("是");
        //查询当前机器信息

        scanDeviceSignDto.setEmpId(emp.getEmpId());
        scanDeviceSignDto.setEmpName(emp.getEmpName());

        scanDeviceSignDto.setWorkshopName(yg01employeefiles.getSector());

        scanDeviceSignDto.setTeamName(emp.getTeamName());
        scanDeviceSignDto.setTeamId(emp.getTeamId());
        scanDeviceSignDto.setClasss(range.getScclass().getDescription());

        scanDeviceSignDto.setDateYmd(range.getDateYmd());

        //如果是产量员工，进行下面操作
        if (flag) {
            Device device = deviceMapper.getById(deviceId);
            //判断是不是产量设备
            Assert.isTrue(device.getProduction1().equals("是"), "该设备不是产量设备，请勿扫码签到！");
            scanDeviceSignDto.setWorkshopName(device.getWorkShop());
            scanDeviceSignDto.setProcessNames(device.getProcess());
            //是否员工已签到?
            LambdaQueryWrapper<ProPersonnelStandConfirm> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ProPersonnelStandConfirm::getStaffId, emp.getEmpId()).eq(ProPersonnelStandConfirm::getClasses, range.getScclass().getDescription()).eq(ProPersonnelStandConfirm::getProcess, device.getProcess()).in(ProPersonnelStandConfirm::getConfirmStatus, ScEnums.ConfirmStatus.CONFIRMED.name(), ScEnums.ConfirmStatus.UNCONFIRMED.name())
                    .last("and DATE(date_ymd)=DATE('" + scanDeviceSignDto.getDateYmd() + "')");
            List<ProPersonnelStandConfirm> confirmList = confirmService.list(queryWrapper);
            List<ScanDeviceDto> currentEmpConfirmDeviceIds = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(confirmList)) {
                Date createTime = confirmList.get(0).getCreateTime();
                scanDeviceSignDto.setCreateTime(createTime);
                scanDeviceSignDto.setSignState("Y");
                confirmList.forEach(cur -> currentEmpConfirmDeviceIds.addAll(parseDeviceIds(cur.getMachineryObj())));
            }

            Map<String, ScanDeviceDto> currentConfirmG = currentEmpConfirmDeviceIds.stream().collect(Collectors.toMap(cur -> cur.getDeviceId() + cur.getAbTag(), Function.identity()));
            //查询当前工序的所有设备
            List<Device> devices = deviceMapper.selectByProcess(device.getProcess());
            List<ScanDeviceDto> scanDeviceDtoList = new ArrayList<>(devices.stream().map(this::getScanDeviceDto).toList());

            if ("细纱".equals(device.getProcess())) {
                //细纱区分A/B
                List<ScanDeviceDto> bList = BeanUtil.copyToList(scanDeviceDtoList, ScanDeviceDto.class);
                scanDeviceDtoList.forEach(cur -> cur.setAbTag("A"));
                bList.forEach(cur -> cur.setAbTag("B"));
                scanDeviceDtoList.addAll(bList);
            }
            scanDeviceSignDto.setScanDeviceDtoList(scanDeviceDtoList);

            //查询当天已被选择的设备
            LambdaQueryWrapper<ProPersonnelStandConfirm> qe = new LambdaQueryWrapper<>();
            qe.eq(ProPersonnelStandConfirm::getClasses, range.getScclass().getDescription())
                    .in(ProPersonnelStandConfirm::getConfirmStatus, ScEnums.ConfirmStatus.CONFIRMED.name(), ScEnums.ConfirmStatus.UNCONFIRMED.name())
                    .isNotNull(ProPersonnelStandConfirm::getMachineryObj)
                    .last("and DATE(date_ymd)=DATE('" + scanDeviceSignDto.getDateYmd() + "')");
            List<ProPersonnelStandConfirm> confirmListMains = confirmService.list(qe);

            List<ScanDeviceDto> allConfirmDeviceIds = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(confirmListMains)) {
                confirmListMains.forEach(cur -> allConfirmDeviceIds.addAll(parseDeviceIds(cur.getMachineryObj())));
                Map<String, ScanDeviceDto> allConfirmG = allConfirmDeviceIds.stream().collect(Collectors.toMap(cur -> cur.getDeviceId() + cur.getAbTag(), Function.identity()));

                for (ScanDeviceDto deviceDto : scanDeviceDtoList) {
                    if (ObjectUtil.isNotNull(allConfirmG.get(deviceDto.getDeviceId() + deviceDto.getAbTag()))) {
                        deviceDto.setDeviceSignState("Y");
                        if (ObjectUtil.isNotNull(currentConfirmG.get(deviceDto.getDeviceId() + deviceDto.getAbTag())))
                            deviceDto.setCurrentFlag("Y");
                    }
                }
            }

            if (CollectionUtil.isNotEmpty(scanDeviceDtoList))
                scanDeviceDtoList.sort(Comparator.comparing(ScanDeviceDto::getDeviceId).thenComparing(ScanDeviceDto::getAbTag));
        }
        else {
            LambdaQueryWrapper<ProPersonnelStandConfirm> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ProPersonnelStandConfirm::getStaffId, emp.getEmpId()).eq(ProPersonnelStandConfirm::getClasses, range.getScclass().getDescription()).in(ProPersonnelStandConfirm::getConfirmStatus, ScEnums.ConfirmStatus.CONFIRMED.name(), ScEnums.ConfirmStatus.UNCONFIRMED.name())
                    .last("and DATE(date_ymd)=DATE('" + scanDeviceSignDto.getDateYmd() + "')");
            List<ProPersonnelStandConfirm> confirmList = confirmService.list(queryWrapper);
            if (CollectionUtil.isNotEmpty(confirmList)){
                scanDeviceSignDto.setSignState("Y");
            }
        }
        return scanDeviceSignDto;
    }

    /**
     * 人员看台确认主表解析出下面的设备
     *
     * @return
     */
    private Collection<ScanDeviceDto> parseDeviceIds(String machineryObj) {

        try {
            return json.<List<ScanDeviceDto>>readValue(machineryObj, new TypeReference<>() {
            });
        } catch (JsonProcessingException e) {
            log.error(e.getMessage());
            throw new BusinessException("解析机台异常");
        }
    }

    private ScanDeviceDto getScanDeviceDto(Device device) {
        ScanDeviceDto scanDeviceDto = new ScanDeviceDto();
        scanDeviceDto.setDeviceId(device.getDeviceId());
        scanDeviceDto.setDeviceCode(device.getDeviceNo());
        scanDeviceDto.setDeviceName(device.getDeviceName());
        scanDeviceDto.setProcessId(device.getProcessId());
        scanDeviceDto.setProcessName(device.getProcess());
        scanDeviceDto.setAbTag("");
        scanDeviceDto.setDeviceSignState("N");
        scanDeviceDto.setCurrentFlag("N");
        return scanDeviceDto;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean submitSign(ScanDeviceSignDto scanDeviceSignDto) {


        ProPersonnelStandConfirm confirm = new ProPersonnelStandConfirm();
        confirm.setDateYmd(scanDeviceSignDto.getDateYmd());//日期
        confirm.setStaffId(scanDeviceSignDto.getEmpId());//员工ID
        confirm.setTeamId(scanDeviceSignDto.getTeamId());//班组ID
        confirm.setTeamName(scanDeviceSignDto.getTeamName());//班组
        confirm.setClasses(scanDeviceSignDto.getClasss());//班次
        confirm.setProcess(scanDeviceSignDto.getProcessNames());//工序
        confirm.setWorkshop(scanDeviceSignDto.getWorkshopName());//车间
        confirm.setConfirmStatus(ScEnums.ConfirmStatus.UNCONFIRMED.name());//班长确认状态
        LambdaQueryWrapper<Yg01employeefiles> yg01LambdaQueryWrapper = new LambdaQueryWrapper<>();
        yg01LambdaQueryWrapper.eq(Yg01employeefiles::getId, scanDeviceSignDto.getEmpId());
        Yg01employeefiles yg01employeefiles = yg01employeefilesService.getOne(yg01LambdaQueryWrapper);
        boolean flag = ObjectUtil.isNotEmpty(yg01employeefiles) && ObjectUtil.isNotEmpty(yg01employeefiles.getProductionOfStaff()) && yg01employeefiles.getProductionOfStaff().equals("是");
        if (!flag) {
            //非产量员工的验证是否重复签到的方式
            LambdaQueryWrapper<ProPersonnelStandConfirm> confirmLambdaQueryWrapper = new LambdaQueryWrapper<>();
            //查看当天，当前班次，当前登录人是否已经签到，如果已经签到不能重复签到
            confirmLambdaQueryWrapper.eq(ProPersonnelStandConfirm::getStaffId, scanDeviceSignDto.getEmpId())
                    .eq(ProPersonnelStandConfirm::getClasses, scanDeviceSignDto.getClasss())
                    .last("and DATE(date_ymd)=DATE('" + scanDeviceSignDto.getDateYmd() + "')");
            Long count = proPersonnelStandConfirmMapper.selectCount(confirmLambdaQueryWrapper);
            Assert.isTrue(count <= 0, "请勿重复签到");
        }
        //如果不是产量员工后面添加机台的逻辑不执行
        else if (flag) {
            List<ScanDeviceDto> scanDeviceDtoList = scanDeviceSignDto.getScanDeviceDtoList();//获取签到的设备列表

            if (CollectionUtil.isEmpty(scanDeviceDtoList)) throw new BusinessException("请选择设备");
            //存在并发问题需校验
            synchronized (this) {
                //查看有没有重复签到机器的
                LambdaQueryWrapper<ProPersonnelStandConfirm> queryWrapper = new LambdaQueryWrapper<>();
                //这个时间，这个班次，这个工序所有打卡和未打卡的机器
                queryWrapper.eq(ProPersonnelStandConfirm::getClasses, confirm.getClasses()).eq(ProPersonnelStandConfirm::getProcess, confirm.getProcess()).in(ProPersonnelStandConfirm::getConfirmStatus, ScEnums.ConfirmStatus.CONFIRMED.getDescription(), ScEnums.ConfirmStatus.UNCONFIRMED.getDescription()).last("and DATE(date_ymd)=DATE('" + scanDeviceSignDto.getDateYmd() + "')");
                List<ProPersonnelStandConfirm> confirmList = confirmService.list(queryWrapper);
                if (CollectionUtil.isNotEmpty(confirmList)) {//如果有
                    Set<ScanDeviceDto> deviceDtos = new HashSet<>();
                    //遍历考勤列表，获得已经被打卡的机器
                    confirmList.forEach(cur -> deviceDtos.addAll(parseDeviceIds(cur.getMachineryObj())));

                    Map<String, ScanDeviceDto> collect = deviceDtos.stream().collect(Collectors.toMap(cur -> cur.getDeviceId() + cur.getAbTag(), Function.identity()));
                    for (ScanDeviceDto deviceDto : scanDeviceDtoList) {
                        if (ObjectUtil.isNotNull(collect.get(deviceDto.getDeviceId() + deviceDto.getAbTag()))) {
                            throw new BusinessException(deviceDto.getDeviceName() + deviceDto.getDeviceCode() + deviceDto.getAbTag() + "已被绑定");
                        }
                    }
                }
            }
            String collect = scanDeviceDtoList.stream().map(ScanDeviceDto::getDeviceCode).collect(Collectors.joining(","));
            confirm.setWorkstation(collect);
            confirm.setMachineryObj("");
            confirm.setCreateUserId(Long.parseLong(scanDeviceSignDto.getEmpId().toString()));
            try {
                confirm.setMachineryObj(json.writeValueAsString(scanDeviceDtoList));
            } catch (JsonProcessingException e) {
                log.error(e.getMessage());
                throw new BusinessException("解析机台异常");
            }
        }

        return confirmService.save(confirm);
    }


    @Override
    public Map<String, Object> getStandConfirmationList(StandConfirmation fo) {

//        Map<String, Map<JSONObject, Collection<ScanDeviceDto>>> resp = new HashMap<>();
        Map<String, Object> resp = new HashMap<>();
        //查询所有工序
//        dictMapper.getDictByCode("SCMa-process").forEach(cur -> resp.put(cur.getLabel(), new HashMap<>()));
        List<Dict> dictByCode = dictMapper.getDictByCode("SCMa-process");
        for (Dict dict : dictByCode) {
            if ((!dict.getLabel().equals("加湿")) && (!dict.getLabel().equals("清花"))) {
                resp.put(dict.getLabel(), new HashMap<>());
            }
        }
        String userId = StpUtil.getLoginId().toString();
        //查询当前登录人的信息
        Emp emp = Optional.ofNullable(empMapper.selectEmpByUserId(userId)).orElseGet(Emp::new);
        //通过员工姓名负责哪个班组，查询班组表，看当前登录人能审核哪个班组
//        String className = classGroupMapper.findClassNameByPrincipalName(emp.getEmpName());
        //查询属于这个班组的所有员工
//        List<Emp> empList = empMapper.empListByClassName(className);
        //查询当前登录人可以考勤的员工
        List<Emp> empList = empMapper.empListByClassName(emp.getEmpName());
        if (CollectionUtil.isEmpty(empList))
            throw new BusinessException("当前登录人所管理的班组未维护员工信息");

        Map<Integer, Emp> empMap = empList.stream().collect(Collectors.toMap(Emp::getEmpId, Function.identity()));

        LambdaQueryWrapper<ProPersonnelStandConfirm> queryWrapper = new LambdaQueryWrapper<>();
        //根据查询条件，在班长确认表中，查询
        queryWrapper.eq(ProPersonnelStandConfirm::getClasses, fo.getClasss()).eq(ProPersonnelStandConfirm::getConfirmStatus, ScEnums.ConfirmStatus.UNCONFIRMED.name())
                .last("and date(date_ymd)=concat('" + fo.getDateYmd() + "')");
        List<ProPersonnelStandConfirm> confirmList = confirmService.list(queryWrapper);
        //区分产量员工和非产量员工，产量员工有工序，非产量员工没有工序
        List<ProPersonnelStandConfirm> productEmp = confirmList.stream().filter(cur -> ObjectUtil.isNotEmpty(cur.getProcess())).collect(Collectors.toList());
        List<ProPersonnelStandConfirm> noProductEmp = confirmList.stream().filter(cur -> ObjectUtil.isEmpty(cur.getProcess())).collect(Collectors.toList());

        //创建返回结果map
        Map<String, Object> resultMap = new HashMap<>();

        if (CollectionUtil.isNotEmpty(noProductEmp)) {
            List<Map<String, Object>> list = new ArrayList<>();
            noProductEmp.forEach(item -> {
                Emp e = empMap.get(item.getStaffId());
                if (ObjectUtil.isNotEmpty(e)) {
                    Map<String, Object> noProductMap = new HashMap<>();
                    noProductMap.put("confirmId", item.getId().toString());
                    noProductMap.put("empId", e.getEmpId());
                    noProductMap.put("empName", e.getEmpName());
                    noProductMap.put("empCode", e.getEmpCode());
                    noProductMap.put("appState", item.getConfirmStatus());
                    noProductMap.put("sector", e.getSector());//部门
                    noProductMap.put("teaName", item.getTeamName());//班组名称
                    noProductMap.put("date_ymd", item.getDateYmd());//打卡时间
                    noProductMap.put("shift", item.getClasses());//班次
                    noProductMap.put("gender", e.getGender());
                    list.add(noProductMap);
                }
            });
            if (!list.isEmpty()) resultMap.put("noProduct", list);
        }


        if (CollectionUtil.isNotEmpty(productEmp)) {
            Map<String, List<ProPersonnelStandConfirm>> processG = productEmp.stream().collect(Collectors.groupingBy(ProPersonnelStandConfirm::getProcess));

            resp.forEach((process, list) -> {
                // 获取当前工序下的所有确认记录
                List<ProPersonnelStandConfirm> proPersonnelStandConfirms = processG.get(process);
                if (CollectionUtil.isEmpty(proPersonnelStandConfirms)) return;

                // 创建用于存储员工及其设备信息的映射
//                HashMap<JSONObject, Collection<ScanDeviceDto>> map = new HashMap<>();
                HashMap<String, Object> map = new HashMap<>();

                // 按员工ID对确认记录进行分组
                Map<Integer, List<ProPersonnelStandConfirm>> empG = proPersonnelStandConfirms.stream()
                        .collect(Collectors.groupingBy(ProPersonnelStandConfirm::getStaffId));

                // 遍历每个员工的确认记录
                for (Integer empId : empG.keySet()) {
                    Emp e = empMap.get(empId); // 获取员工信息

                    if (ObjectUtil.isEmpty(e)) continue;
                    List<ProPersonnelStandConfirm> personnelStandConfirms = empG.get(empId);
                    ProPersonnelStandConfirm confirm = personnelStandConfirms.get(0); // 取第一条记录作为代表

                    // 解析该记录中包含的设备列表
                    Collection<ScanDeviceDto> scanDeviceDtoList = parseDeviceIds(confirm.getMachineryObj());

                    // 构建返回给前端的JSON对象，包含员工和确认状态信息
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("confirmId", confirm.getId().toString());
                    jsonObject.put("empId", e.getEmpId());
                    jsonObject.put("empName", e.getEmpName());
                    jsonObject.put("empCode", e.getEmpCode());
                    jsonObject.put("appState", confirm.getConfirmStatus());

                    // 将员工信息与设备列表关联
//                    map.put(jsonObject, scanDeviceDtoList);
                    map.put("empInfo", jsonObject);
                    map.put("deviceInfo", scanDeviceDtoList);
                }

                // 更新最终结果中的工序对应数据
                resp.put(process, map);
            });
            if (!resp.isEmpty()) resultMap.put("product", resp);
        }


        return resultMap;

    }

    @Override
    public Boolean reject(Long id) {
//        return confirmService.removeById(id);
        ProPersonnelStandConfirm confirm = confirmService.getById(id);
        confirm.setConfirmStatus(ScEnums.ConfirmStatus.REJECT.name());
        return confirmService.updateById(confirm);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean confirm(List<Long> confirmIds) {
        if (CollectionUtil.isEmpty(confirmIds)) throw new BusinessException("请选择待确认签到数据");

        Set<ProPersonnelStandConfirm> updateList = confirmIds.stream().map(id -> {
            ProPersonnelStandConfirm confirm = new ProPersonnelStandConfirm();
            confirm.setConfirmStatus(ScEnums.ConfirmStatus.CONFIRMED.name());
            confirm.setId(id);
            return confirm;
        }).collect(Collectors.toSet());
        confirmService.updateBatchById(updateList);

        List<ProPersonnelStandConfirm> standConfirmList = confirmService.listByIds(confirmIds);

        Map<Integer, String> empMap = empMapper.getEmpList().stream().collect(Collectors.toMap(Emp::getEmpId, Emp::getEmpName));

        CopyOptions copyOptions = new CopyOptions();
        copyOptions.setIgnoreProperties("id", "confirmStatus", "createUserId", "createTime", "remark");
        List<ProPersonnelStand> stands = BeanUtil.copyToList(standConfirmList, ProPersonnelStand.class, copyOptions);
        List<ProPersonnelStandMachine> machines = new ArrayList<>();

        for (ProPersonnelStand stand : stands) {
//            Collection<ScanDeviceDto> scanDeviceDtos = parseDeviceIds(stand.getMachineryObj());
            if (StringUtil.isEmpty(stand.getMachineryObj())) continue;
            Collection<ScanDeviceDto> scanDeviceDtos = parseDeviceIds(stand.getMachineryObj());
            stand.setId(IdUtil.getSnowflake(1, 1).nextId());
            for (ScanDeviceDto scanDeviceDto : scanDeviceDtos) {
                ProPersonnelStandMachine machine = new ProPersonnelStandMachine();
                machine.setDeviceId(scanDeviceDto.getDeviceId());
                machine.setProcessId(scanDeviceDto.getProcessId());
                machine.setPersonnelStandId(stand.getId());
                machine.setAbTag(scanDeviceDto.getAbTag());
                machine.setWorkshop(stand.getWorkshop());
                machine.setHasDivideOutput("细纱".equals(stand.getProcess()) ? "Y" : "N");
                machine.setDeviceCode(scanDeviceDto.getDeviceCode());
                machines.add(machine);
            }

        }

        Map<Long, List<ProPersonnelStandMachine>> collect = machines.stream().collect(Collectors.groupingBy(ProPersonnelStandMachine::getPersonnelStandId));

        stands.forEach(cur -> {
            cur.setStaffName(empMap.get(cur.getStaffId()));
            List<ProPersonnelStandMachine> machineList = collect.get(cur.getId());
            if (machineList != null) {
                String s = machineList.stream().map(cur1 -> cur1.getDeviceCode() + cur1.getAbTag()).collect(Collectors.joining(","));
                cur.setWorkstation(s);
                cur.setTimeRange(ScEnums.SCCLASS.AM.name().equals(cur.getClasses()) ? "09:30-21:30" : "21:30-09:30");
                double standCount = 0;
                for (ProPersonnelStandMachine machine : machineList)
                    standCount += "Y".equals(machine.getHasDivideOutput()) ? 0.5 : 1;
                cur.setStandCount(standCount);
                cur.setCreateUserId(Long.parseLong(SCUtil.getCurrentLoginEmp().getEmpId().toString()));
            }
        });
        proPersonnelStandService.saveBatch(stands);
        personnelStandMachineService.saveBatch(machines);
        Emp currentLoginEmp = SCUtil.getCurrentLoginEmp();
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.execute(() -> {
            try {
                addJx01StaffAttendanceLog(standConfirmList,currentLoginEmp);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        executorService.shutdown();

        return Boolean.TRUE;
    }

    @Override
    public List<Map<String, Object>> getChackInHistory() {
        Emp currentLoginEmp = SCUtil.getCurrentLoginEmp();
        Assert.isTrue(currentLoginEmp != null, "未登录或登录过期");
        Integer empId = currentLoginEmp.getEmpId();
        List<Map<String, Object>> list = proPersonnelStandConfirmMapper.selecthackInHistory(empId);
        for (Map<String, Object> map : list) {
            Object dateYmd = map.get("date_ymd");
            String dateYmdFormat = dateYmd.toString().replace("T", " ");
            map.put("date_ymd", dateYmdFormat);
        }
        return list;
    }

    @Autowired
    private Jx01staffattendancelogMapper jx01staffattendancelogMapper;

    @Autowired
    private Yg01employeefilesMapper yg01employeefilesMapper;

    @Autowired
    protected Grouptableyg02Mapper grouptableyg02Mapper;

    @Transactional(rollbackFor = Exception.class,propagation= Propagation.REQUIRES_NEW)
    public void addJx01StaffAttendanceLog(List<ProPersonnelStandConfirm> standConfirmList,Emp currentLoginEmp) {
        //员工可能重复扫码看台

        Set<Integer> empIds = standConfirmList.stream().map(ProPersonnelStandConfirm::getStaffId).collect(Collectors.toSet());
        LambdaQueryWrapper<Yg01employeefiles> yg01employeefilesLambdaQueryWrapper = new LambdaQueryWrapper<>();
        yg01employeefilesLambdaQueryWrapper.in(Yg01employeefiles::getId, empIds);
        List<Yg01employeefiles> yg01employeefilesList = yg01employeefilesMapper.selectList(yg01employeefilesLambdaQueryWrapper);

        List<String> empIdNumberList = yg01employeefilesList.stream().map(Yg01employeefiles::getIdNumber).toList();
        LambdaQueryWrapper<Jx01staffattendancelog> jx01staffattendancelogLambdaQueryWrapper = new LambdaQueryWrapper<>();
        jx01staffattendancelogLambdaQueryWrapper.in(Jx01staffattendancelog::getIdnumber5, empIdNumberList)
                .eq(Jx01staffattendancelog::getDateofattendance, DateUtil.format(new Date(), "yyyy-MM-dd"));
        List<Jx01staffattendancelog> jx01staffattendancelogList = jx01staffattendancelogMapper.selectList(jx01staffattendancelogLambdaQueryWrapper);
        if (CollectionUtil.isNotEmpty(jx01staffattendancelogList)) {
            yg01employeefilesList.removeIf(new Predicate<Yg01employeefiles>() {
                @Override
                public boolean test(Yg01employeefiles yg01employeefiles) {
                    for (Jx01staffattendancelog jx01staffattendancelog : jx01staffattendancelogList) {
                        if (jx01staffattendancelog.getIdnumber5().equals(yg01employeefiles.getIdNumber())) {
                            return true;
                        }
                    }
                    return false;
                }
            });
        }
        if (CollectionUtil.isEmpty(yg01employeefilesList)) return;

        Map<Integer, List<Yg01employeefiles>> yg01GroupById = yg01employeefilesList.stream().collect(Collectors.groupingBy(Yg01employeefiles::getId));

        Map<Integer, List<ProPersonnelStandConfirm>> confirmGroupByStaffId = standConfirmList.stream().collect(Collectors.groupingBy(ProPersonnelStandConfirm::getStaffId));

        for (Integer empId : empIds) {
            List<ProPersonnelStandConfirm> proPersonnelStandConfirms = confirmGroupByStaffId.get(empId);
            ProPersonnelStandConfirm confirm = proPersonnelStandConfirms.get(0);

            List<Yg01employeefiles> yg01employeefilesListById = yg01GroupById.get(empId);
            Jx01staffattendancelog jx01staffattendancelog = new Jx01staffattendancelog();
            CopyOptions copyOptions = new CopyOptions();
            copyOptions.setIgnoreProperties("id", "createTime", "updateTime");
            BeanUtil.copyProperties(yg01employeefilesListById.get(0), jx01staffattendancelog, copyOptions);
            jx01staffattendancelog.setCode5(yg01employeefilesListById.get(0).getCode().longValue());//工号
            jx01staffattendancelog.setIdnumber5(yg01employeefilesListById.get(0).getIdNumber());//身份证号
            jx01staffattendancelog.setNameofemployee(yg01employeefilesListById.get(0).getName());//员工姓名

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String dateofAttendance = LocalDateTime.parse(confirm.getDateYmd(), formatter).format(formatter);
            jx01staffattendancelog.setDateofattendance(dateofAttendance);//出勤日期
            jx01staffattendancelog.setWorkshop(confirm.getWorkshop());//车间
            jx01staffattendancelog.setAttendance1(confirm.getClasses());//出勤班次
            jx01staffattendancelog.setActualdutystations(yg01employeefilesListById.get(0).getPositions());//岗位
            jx01staffattendancelog.setStateofattendance("出勤");//出勤状态

            LambdaQueryWrapper<Grouptableyg02> grouptableyg02LambdaQueryWrapper = new LambdaQueryWrapper<>();
            grouptableyg02LambdaQueryWrapper.eq(Grouptableyg02::getClassname, yg01employeefilesList.get(0).getClass55());
            Grouptableyg02 grouptableyg02 = grouptableyg02Mapper.selectOne(grouptableyg02LambdaQueryWrapper);
            Long actualHoursWorked = grouptableyg02.getTypeofattendance().equals("长白班") ? 12L : 8L;

            jx01staffattendancelog.setActualhoursworked(actualHoursWorked);
            jx01staffattendancelog.setAttendanceconfirmed("已确认");
            jx01staffattendancelogMapper.insert(jx01staffattendancelog);
        }
        saveOrUpdateGroupTableYg02(yg01employeefilesList,currentLoginEmp);

    }

    @Autowired
    private Groupattendancestatisticsforjx02Mapper groupattendancestatisticsforjx02Mapper;
    @Autowired
    private LeaveApplicationMapper leaveApplicationMapper;

    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdateGroupTableYg02(List<Yg01employeefiles> yg01employeefilesList,Emp currentLoginEmp) {
        Map<String, List<Yg01employeefiles>> collect = yg01employeefilesList.stream().collect(Collectors.groupingBy(Yg01employeefiles::getClass55));
        Set<String> keySet = collect.keySet();
        for (String key : keySet) {
            List<Yg01employeefiles> yg01employeefiles = collect.get(key);
            String classes = yg01employeefiles.get(0).getClasses();
            LambdaQueryWrapper<Groupattendancestatisticsforjx02> groupattendancestatisticsforjx02LambdaQueryWrapper = new LambdaQueryWrapper<>();
            groupattendancestatisticsforjx02LambdaQueryWrapper.eq(Groupattendancestatisticsforjx02::getAttendance, key);
            groupattendancestatisticsforjx02LambdaQueryWrapper.eq(Groupattendancestatisticsforjx02::getTeamleaderlogisticsmanagement, classes);
            List<Groupattendancestatisticsforjx02> groupattendancestatisticsforjx02List = groupattendancestatisticsforjx02Mapper.selectList(groupattendancestatisticsforjx02LambdaQueryWrapper);
            Groupattendancestatisticsforjx02 groupattendancestatisticsforjx02 = new Groupattendancestatisticsforjx02();
            if (CollectionUtil.isNotEmpty(groupattendancestatisticsforjx02List)) {
                groupattendancestatisticsforjx02 = groupattendancestatisticsforjx02List.get(0);

            }
            LambdaQueryWrapper<Yg01employeefiles> curLoginEmpCanAttendance = new LambdaQueryWrapper<>();
            curLoginEmpCanAttendance.eq(Yg01employeefiles::getClass55, key)
                    .eq(Yg01employeefiles::getClasses, classes)
                    .eq(Yg01employeefiles::getActiveOrNot, "在职");
            //考勤员工数
            Long curLoginEmpCanAttendanceNum = yg01employeefilesMapper.selectCount(curLoginEmpCanAttendance);
            groupattendancestatisticsforjx02.setNumberofstaffinattendance(curLoginEmpCanAttendanceNum);
            //离职人数
            curLoginEmpCanAttendance = new LambdaQueryWrapper<>();
            curLoginEmpCanAttendance.eq(Yg01employeefiles::getClass55, key)
                    .eq(Yg01employeefiles::getClasses, classes)
                    .eq(Yg01employeefiles::getActiveOrNot, "离职");
            Long curLoginEmpCanAttendanceQuitNum = yg01employeefilesMapper.selectCount(curLoginEmpCanAttendance);
            //离职人数
            groupattendancestatisticsforjx02.setSeparations1(curLoginEmpCanAttendanceQuitNum);
            //出勤人数
            groupattendancestatisticsforjx02.setNumberofpersonsinattendance(groupattendancestatisticsforjx02.getNumberofpersonsinattendance() + yg01employeefiles.size());

            //休息人数
            int count = leaveApplicationMapper.selectRestNum(currentLoginEmp.getEmpName(),key);
            groupattendancestatisticsforjx02.setNumberofpersonsresting(Long.valueOf(count));
            //缺勤人数=考勤人数-出勤人数-休息人数
            groupattendancestatisticsforjx02.setNumberofabsentees(groupattendancestatisticsforjx02.getNumberofstaffinattendance() - groupattendancestatisticsforjx02.getNumberofpersonsinattendance()-groupattendancestatisticsforjx02.getNumberofpersonsresting());

            //考勤班组
            groupattendancestatisticsforjx02.setAttendance(key);
            //班组长
            groupattendancestatisticsforjx02.setTeamleaderlogisticsmanagement(classes);
            //考勤日期
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            groupattendancestatisticsforjx02.setDateofattendance(new Date());
            if (groupattendancestatisticsforjx02.getId()==null){
                groupattendancestatisticsforjx02Mapper.insert(groupattendancestatisticsforjx02);
            }
            else {
                groupattendancestatisticsforjx02Mapper.updateById(groupattendancestatisticsforjx02);
            }
        }
    }

    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String parse = LocalDateTime.parse("2025-08-06 09:30:20", formatter).format(formatter);
        System.out.println(parse);
    }

}
